﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using FireStarter.Base;
using FireStarter.CodeGeneration;
using FireStarter.CodeGeneration.Generator;
using FireStarter.CodeGeneration.Parser;
using FireStarterModeller.BO;
using Habanero.Base;
using NUnit.Framework;

namespace FireStarter.Test.CodeGeneration.Templates
{
    [TestFixture]
    public class TestBODef : TestBase
    {
        [Test]
        public void Test_PropertyGenerated_IfGenerateCodeIsTrue()
        {
            //---------------Set up test pack-------------------
            string className = TestUtilsCodeGen.GetRandomString();
            DMProperty dmProperty;
            DMSolution dmSolution = CreateDmSolutionWithOneProperty(className, out dmProperty);
            string propertyName = dmProperty.PropertyName;

            string projectPath = TestUtilsCodeGen.GetRandomString();

            BoProjectGenerator projectGenerator = CreateProjectGenerator(dmSolution, projectPath);
            //-------------Assert Preconditions ----------------
            Assert.IsTrue(dmProperty.GenerateCode);
            //---------------Execute Test ----------------------
            Result result = projectGenerator.Generate();
            //---------------Test Result -----------------------
            Assert.IsTrue(result.Successful);
            string filePath = Path.Combine(projectPath, className) + ".Def.cs";
            Assert.IsTrue(File.Exists(filePath));
            string fileContents = File.ReadAllText(filePath);
            StringAssert.Contains(String.Format("public virtual System.object {0}", propertyName), fileContents);
            StringAssert.Contains(String.Format(@"return ((System.object)(base.GetPropertyValue(""{0}"")));", propertyName), fileContents);
            //---------------Tear Down--------------------------
            Directory.Delete(projectPath, true);
        }

        [Test]
        public void Test_PropertyNotGenerated_IfGenerateCodeIsFalse()
        {
            string className = TestUtilsCodeGen.GetRandomString();
            DMProperty dmProperty;
            DMSolution dmSolution = CreateDmSolutionWithOneProperty(className, out dmProperty);
            string propertyName = dmProperty.PropertyName;
            dmProperty.GenerateCode = false;
            string projectPath = TestUtilsCodeGen.GetRandomString();

            BoProjectGenerator projectGenerator = CreateProjectGenerator(dmSolution, projectPath);
            //-------------Assert Preconditions ----------------
            Assert.IsFalse(dmProperty.GenerateCode);
            //---------------Execute Test ----------------------
            Result result = projectGenerator.Generate();
            //---------------Test Result -----------------------
            Assert.IsTrue(result.Successful);
            string filePath = Path.Combine(projectPath, className) + ".Def.cs";
            Assert.IsTrue(File.Exists(filePath));
            string fileContents = File.ReadAllText(filePath);
            Assert.IsFalse(fileContents.Contains(String.Format("public virtual System.object {0}", propertyName)));
            //---------------Tear Down--------------------------
            Directory.Delete(projectPath, true);
        }

        [Test]
        public void Test_RelationshipGenerated_IfGenerateCodeIsTrue()
        {
            //---------------Set up test pack-------------------
            string className = TestUtilsCodeGen.GetRandomString();
            DMRelationship dmRelationship;
            DMSolution dmSolution = CreateDmSolutionWithOneRelationship(className, out dmRelationship);
            string relationshipName = dmRelationship.RelationshipName;
            string relatedClassName = dmRelationship.RelatedClassName;

            string projectPath = TestUtilsCodeGen.GetRandomString();

            BoProjectGenerator projectGenerator = CreateProjectGenerator(dmSolution, projectPath);
            //-------------Assert Preconditions ----------------
            Assert.IsTrue(dmRelationship.GenerateCode);
            //---------------Execute Test ----------------------
            Result result = projectGenerator.Generate();
            //---------------Test Result -----------------------
            Assert.IsTrue(result.Successful);
            string filePath = Path.Combine(projectPath, className) + ".Def.cs";
            Assert.IsTrue(File.Exists(filePath));
            string fileContents = File.ReadAllText(filePath);
            StringAssert.Contains(String.Format("public virtual {0}.{1} {2}", dmRelationship.RelatedAssemblyName, relatedClassName, relationshipName),
                                  fileContents);
            StringAssert.Contains(String.Format(
                                  @"return Relationships.GetRelatedObject<{0}.{1}>(""{2}"");",
                                  dmRelationship.RelatedAssemblyName, relatedClassName, relationshipName), fileContents);
            //---------------Tear Down--------------------------
            Directory.Delete(projectPath, true);
        }

        [Test]
        public void Test_RelationshipNotGenerated_IfGenerateCodeIsFalse()
        {
            //---------------Set up test pack-------------------
            string className = TestUtilsCodeGen.GetRandomString();
            DMRelationship dmRelationship;
            DMSolution dmSolution = CreateDmSolutionWithOneRelationship(className, out dmRelationship);
            string relationshipName = dmRelationship.RelationshipName;
            string relatedClassName = dmRelationship.RelatedClassName;
            dmRelationship.GenerateCode = false;
            string projectPath = TestUtilsCodeGen.GetRandomString();

            BoProjectGenerator projectGenerator = CreateProjectGenerator(dmSolution, projectPath);
            //-------------Assert Preconditions ----------------
            Assert.IsFalse(dmRelationship.GenerateCode);
            //---------------Execute Test ----------------------
            Result result = projectGenerator.Generate();
            //---------------Test Result -----------------------
            Assert.IsTrue(result.Successful);
            string filePath = Path.Combine(projectPath, className) + ".Def.cs";
            Assert.IsTrue(File.Exists(filePath));
            string fileContents = File.ReadAllText(filePath);
            StringAssert.DoesNotContain(String.Format("public virtual {0}.{1} {2}", dmRelationship.RelatedAssemblyName, relatedClassName, relationshipName),
                                  fileContents);
            StringAssert.DoesNotContain(String.Format(
                                  @"return Relationships.GetRelatedObject<{0}.{1}>(""{2}"");",
                                  dmRelationship.RelatedAssemblyName, relatedClassName, relationshipName), fileContents);
            //---------------Tear Down--------------------------
            Directory.Delete(projectPath, true);
        }
     

        private static DMSolution CreateDmSolutionWithOneProperty(string className, out DMProperty dmProperty)
        {
            DMSolution dmSolution = new DMSolution();
            dmSolution.ApplicationName = TestUtilsCodeGen.GetRandomString();
            DMAssembly dmAssembly = new DMAssembly();
            dmSolution.DefaultAssembly = dmAssembly;
            DMClass dmClass = dmAssembly.Classes.CreateBusinessObject();
            dmClass.ClassNameBO = className;
            dmProperty = dmClass.Properties.CreateBusinessObject();
            dmProperty.PropertyName = TestUtilsCodeGen.GetRandomString();
            dmProperty.PropertyType = new DMPropertyType("System", "object");
            return dmSolution;
        }

        private static DMSolution CreateDmSolutionWithOneRelationship(string className, out DMRelationship dmRelationship)
        {
            DMProperty dmProperty;
            DMSolution dmSolution = CreateDmSolutionWithOneProperty(className, out dmProperty);
            dmRelationship = dmProperty.Class.RelationshipsDM.CreateBusinessObject();
            dmRelationship.RelationshipName = TestUtilsCodeGen.GetRandomString();

            DMClass relatedClass = dmSolution.DefaultAssembly.Classes.CreateBusinessObject();
            string relatedClassName = TestUtilsCodeGen.GetRandomString();
            relatedClass.ClassNameBO = relatedClassName;
            relatedClass.Assembly.AssemblyName = TestUtilsCodeGen.GetRandomString();
            dmRelationship.RelatedClass = relatedClass;
            return dmSolution;
        }

        private static BoProjectGenerator CreateProjectGenerator(DMSolution dmSolution, string projectPath)
        {
            SolutionGenerator solutionGenerator = new SolutionGenerator();
            solutionGenerator.HabaneroReferencePath = TestUtilsCodeGen.GetRandomString();
            solutionGenerator.ModelSolution = dmSolution;
            solutionGenerator.ModelClasses = ((IModelSolution)dmSolution).ModelClasses;

            BoProjectGenerator projectGenerator = new BoProjectGenerator();
            projectGenerator.SolutionGenerator = solutionGenerator;
            projectGenerator.ProjectName = TestUtilsCodeGen.GetRandomString();
            projectGenerator.ProjectPath = projectPath;
            return projectGenerator;
        }
    }
}
